#ifndef LEVEL_H
#define LEVEL_H

#include <GL/glut.h>
#include <vector>
#include <string>
#include <cmath>

#include "GlobalSettings.h"
#include "UtilFunctions.h"
#include "MathMisc.h"
#include "Disk.h"

using namespace std;

class Level
{
	public:
		friend class MegaMan;
		Level ();

		bool LoadLevel(char *filename);

		void Update ();
		bool LoadTextures();

		Quad GetCell(int x, int y);

		Level & operator = (Level * level)
		{
			baseHeight = level->baseHeight;
			texture = level->texture;
			MapData = level->MapData;
		}

	private:
		float baseHeight;
		vector<GLuint> texture;
		vector< vector <Quad> > MapData;

		void BakeMap();
		void doHill(int x1, int y1, int x2, int y2, int height);
		
		
};

Level::Level()
{
	texture.resize(1);
}

bool Level::LoadLevel(char *filename)
{
	Disk data(filename, "r");
	while (data.readLine())
	{
		if(data.getLine().size())
		{
			vector<string> line  = data.getLine();

			if (line[0] == "mapsize")
			{
				if(line.size() != 4)
					return false;
				int x = atoi(line[1].c_str());
				int y = atoi(line[2].c_str());
				baseHeight = atoi(line[3].c_str()) * 16;
				MapData.resize(x);
				for(int i = 0; i < x; i++)
					MapData[i].resize(y);
				BakeMap();
			}
			else if (line[0] == "hill")
			{
				if (line.size() != 6)
					return false;
				int x1 = atoi(line[1].c_str());
				int y1 = atoi(line[2].c_str());
				int x2 = atoi(line[3].c_str());
				int y2 = atoi(line[4].c_str());
				int h = atoi(line[5].c_str()) * 16;

				doHill(x1,y1,x2,y2,h);
			}
		}

	}
	return true;
}

void Level::Update()
{
	// Bind Texture
	glBindTexture(GL_TEXTURE_2D, texture[0]);

	// Draw ground
	glColor3f(0.0f, 1.0f, 0.0);
	glBegin(GL_QUADS);
	for (int x = 0; x < MapData.size(); x++)
		{
			for (int y = 0; y < MapData[x].size(); y++)
			{	
				GLVertex(MapData[x][y]);
			}
		}
	glEnd();
}

bool Level::LoadTextures()
{
	return LoadGLTextures(texture[0], "grass.bmp",0);
}

Quad Level::GetCell(int x, int y)
{
	if (x < MapData.size() && y < MapData.size() && x > 0 && y > 0)
		return MapData[x][y];
	else
	{
		Quad Dummy;
		Dummy.angle = 90;
		return Dummy;
	}
}

void Level::BakeMap()
{
	for(int x = 0; x < MapData.size(); x++)
	{
		for(int y = 0; y < MapData[x].size(); y++)
		{
			MapData[x][y].BottomLeft(x*CELLWIDTH, baseHeight, y*CELLWIDTH);
			MapData[x][y].TopLeft(x*CELLWIDTH, baseHeight, (y+1)*CELLWIDTH);
			MapData[x][y].TopRight((x+1)*CELLWIDTH, baseHeight, (y+1)*CELLWIDTH);
			MapData[x][y].BottomRight((x+1)*CELLWIDTH, baseHeight, y*CELLWIDTH);
		}
	}
}

void Level::doHill(int x1, int y1, int x2, int y2, int height)
{
	float heightMin, heightMax, tmp;
	for (int x = x1; x < x2; x++)
	{
		for (int y = y1; y < y2; y++)
		{
			// Raise the cell
			MapData[x][y].BottomLeft.y = height;
			MapData[x][y].BottomRight.y = height;
			MapData[x][y].TopLeft.y = height;
			MapData[x][y].TopRight.y = height;
			MapData[x][y].avgheight = height;
			MapData[x][y].orientation = -1;

			// Top Left Corner
			if (MapData[x-1][y+1].orientation == -1)
			{
				for(int i = 0; i < 4; i++)
					if (MapData[x-1][y+1][i].y != height)
						MapData[x-1][y+1].orientation = DOWNRIGHT;
			}
			else
				MapData[x-1][y+1].orientation = DOWNRIGHT;
			MapData[x-1][y+1].BottomRight.y = height;
			MapData[x-1][y+1].avgheight = AverageHeight(MapData[x-1][y+1], height);
			tmp = CELLDIAGL;
			MapData[x-1][y+1].angle = ToDegree(atan(MapData[x-1][y+1].avgheight/tmp));

			// Top
			if (MapData[x][y+1].orientation == -1)
			{
				for(int i = 0; i < 4; i++)
					if (MapData[x][y+1][i].y != height)
						MapData[x][y+1].orientation = DOWN;
			}
			else
				MapData[x][y+1].orientation = DOWN;
			MapData[x][y+1].BottomLeft.y = height;
			MapData[x][y+1].BottomRight.y = height;
			MapData[x][y+1].avgheight = AverageHeight(MapData[x][y+1], height);
			tmp = CELLWIDTH;
			MapData[x][y+1].angle = ToDegree(atan(MapData[x][y+1].avgheight/tmp));

			// Top Right Corner
			if (MapData[x+1][y+1].orientation == -1)
			{
				for(int i = 0; i < 4; i++)
					if (MapData[x+1][y+1][i].y != height)
						MapData[x+1][y+1].orientation = DOWNLEFT;
			}
			else
				MapData[x+1][y+1].orientation = DOWNLEFT;
			MapData[x+1][y+1].BottomLeft.y = height;
			MapData[x+1][y+1].avgheight = AverageHeight(MapData[x+1][y+1], height);
			tmp = CELLDIAGL;
			MapData[x+1][y+1].angle = ToDegree(atan(MapData[x+1][y+1].avgheight/tmp));

			// Right
			if (MapData[x+1][y].orientation == -1)
			{
				for(int i = 0; i < 4; i++)
					if (MapData[x+1][y][i].y != height)
						MapData[x+1][y].orientation = LEFT;
			}
			else
				MapData[x+1][y].orientation = LEFT;
			MapData[x+1][y].BottomLeft.y = height;
			MapData[x+1][y].TopLeft.y = height;
			MapData[x+1][y].avgheight = AverageHeight(MapData[x+1][y], height);
			tmp = CELLWIDTH;
			MapData[x+1][y].angle = ToDegree(atan(MapData[x+1][y].avgheight/tmp));

			// Bottom Right Corner
			if (MapData[x+1][y-1].orientation == -1)
			{
				for(int i = 0; i < 4; i++)
					if (MapData[x+1][y-1][i].y != height)
						MapData[x+1][y-1].orientation = UPLEFT;
			}
			else
				MapData[x+1][y-1].orientation = UPLEFT;
			MapData[x+1][y-1].TopLeft.y = height;
			MapData[x+1][y-1].avgheight = AverageHeight(MapData[x+1][y-1], height);
			tmp = CELLDIAGL;
			MapData[x+1][y-1].angle = ToDegree(atan(MapData[x+1][y-1].avgheight/tmp));
			
			// Bottom
			if (MapData[x][y-1].orientation == -1)
			{
				for(int i = 0; i < 4; i++)
					if (MapData[x][y-1][i].y != height)
						MapData[x][y-1].orientation = UP;
			}
			else
				MapData[x][y-1].orientation = UP;
			MapData[x][y-1].TopLeft.y = height;
			MapData[x][y-1].TopRight.y = height;
			MapData[x][y-1].avgheight = AverageHeight(MapData[x][y-1], height);
			tmp = CELLWIDTH;
			MapData[x][y-1].angle = ToDegree(atan(MapData[x][y-1].avgheight/tmp));

			// Bottom Left Corner
			if (MapData[x-1][y-1].orientation == -1)
			{
				for(int i = 0; i < 4; i++)
					if (MapData[x-1][y-1][i].y != height)
						MapData[x-1][y-1].orientation = UPRIGHT;
			}
			else
				MapData[x-1][y-1].orientation = UPRIGHT;
			MapData[x-1][y-1].TopRight.y = height;
			MapData[x-1][y-1].avgheight = AverageHeight(MapData[x-1][y-1], height);
			tmp = CELLDIAGL;
			MapData[x-1][y-1].angle = ToDegree(atan(MapData[x-1][y-1].avgheight/tmp));

			// Left
			if (MapData[x-1][y].orientation == -1)
			{
				for(int i = 0; i < 4; i++)
					if (MapData[x-1][y][i].y != height)
						MapData[x-1][y].orientation = RIGHT;
			}
			else
				MapData[x-1][y].orientation = RIGHT;
			MapData[x-1][y].TopRight.y = height;
			MapData[x-1][y].BottomRight.y = height;
			MapData[x-1][y].avgheight = AverageHeight(MapData[x-1][y], height);
			tmp = CELLWIDTH;
			MapData[x-1][y].angle = ToDegree(atan(MapData[x-1][y].avgheight/tmp));
			MapData[x-1][y].orientation = RIGHT;
		}
	}
}

#endif
